﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using System.Collections;
using Twodi.Utility;
using Twodi.Behavior.Interfaces;
using Twodi.Interfaces;

namespace Twodi.Screen
{
    /// <summary>
    /// Gerenciador de telas do jogo.
    /// </summary>
    public class Screens : DrawableGameComponent, IKeyboardHandler, IMouseHandler
    {
        /// <summary>
        /// Telas do jogo.
        /// </summary>
        private static Dictionary<String, Screen> screens;

        /// <summary>
        /// Nome da tela atual do jogo.
        /// </summary>
        public static String Name { get; set; }

        /// <summary>
        /// Construtor padrão.
        /// </summary>
        /// <param name="game">Jogo cujo componente esta associado.</param>
        public Screens(Game game)
            : base(game)
        {
            Name = "";
            screens = new Dictionary<string, Screen>();
        }

        /// <summary>
        /// Inicializar tela atual.
        /// </summary>
        public static new void Initialize()
        {
            if (screens.ContainsKey(Name)) screens[Name].Initialize();
            else
            {
                if (Name == string.Empty) Console.WriteLine("Screens doesn't contains active screen. Initialize should be called after added screens.");
                else Console.WriteLine("Screens doesn't contains Screen with name '" + Name + "'. Screen couldn't be Initialized.");
            }
        }

        /// <summary>
        /// Atualizar tela atual.
        /// </summary>
        /// <param name="gameTime"></param>
        public override void Update(GameTime gameTime)
        {
            if (Enabled) screens[Name].Update(gameTime);
            base.Update(gameTime);
        }

        /// <summary>
        /// Renderizar tela atual.
        /// </summary>
        /// <param name="gameTime"></param>
        public override void Draw(GameTime gameTime)
        {
            if (Visible) screens[Name].Draw(gameTime);
            base.Draw(gameTime);
        }

        /// <summary>
        /// Adicionar tela.
        /// </summary>
        /// <param name="key">Chave/Nome da tela.</param>
        /// <param name="value">Tela.</param>
        public static void Add(string key, Screen value)
        {
            if (Helper.isEmpty(Name)) Name = key;
            screens.Add(key, value);
        }

        /// <summary>
        /// Verificar se contem chave/nome da tela.
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static bool ContainsKey(string key)
        {
            return screens.ContainsKey(key);
        }

        /// <summary>
        /// Chaves/Nomes das telas do gerenciador.
        /// </summary>
        public static ICollection<string> Keys
        {
            get { return screens.Keys; }
        }

        /// <summary>
        /// Remover tela com chave/nome especificado.
        /// </summary>
        /// <param name="key">Chave/Nome da tela.</param>
        /// <returns></returns>
        public static bool Remove(string key)
        {
            return screens.Remove(key);
        }

        /// <summary>
        /// Tentar pegar tela pela chave/nome, jogando no valor.
        /// </summary>
        /// <param name="key">Chave/Nome da tela.</param>
        /// <param name="value">Tela que será populada.</param>
        /// <returns></returns>
        public static bool TryGetValue(string key, out Screen value)
        {
            return screens.TryGetValue(key, out value);
        }

        /// <summary>
        /// Telas do gerenciador.
        /// </summary>
        public static ICollection<Screen> Values
        {
            get { return screens.Values; }
        }

        /// <summary>
        /// Atual tela ativa do gerenciador.
        /// </summary>
        public static Screen Screen
        {
            get
            {
                return screens[Name];
            }
        }

        /// <summary>
        /// Adicionar item a lista de telas.
        /// </summary>
        /// <param name="item">Item contendo chave/nome e tela.</param>
        public static void Add(KeyValuePair<string, Screen> item)
        {
            screens.Add(item.Key, item.Value);
        }

        /// <summary>
        /// Limpar telas do gerenciador.
        /// </summary>
        public static void Clear()
        {
            screens.Clear();
        }

        /// <summary>
        /// Verificar se contem chave/nome e tela no gerenciador.
        /// </summary>
        /// <param name="item">Item contendo chave/nome e tela.</param>
        /// <returns></returns>
        public static bool Contains(KeyValuePair<string, Screen> item)
        {
            return screens.Contains(item);
        }

        /// <summary>
        /// Quantidade de telas no gerenciador.
        /// </summary>
        public int Count
        {
            get { return screens.Count; }
        }

        /// <summary>
        /// Remover tela utilizando item.
        /// </summary>
        /// <param name="item">Item contendo chave/nome e tela.</param>
        /// <returns></returns>
        public static bool Remove(KeyValuePair<string, Screen> item)
        {
            return screens.Remove(item.Key);
        }

        /// <summary>
        /// Criar Enumerator do Gerenciador.
        /// </summary>
        /// <returns></returns>
        public static IEnumerator<KeyValuePair<string, Screen>> GetEnumerator()
        {
            return screens.GetEnumerator();
        }

        public bool Handle(Input.KeyboardInput input)
        {
            if (Enabled) return screens[Name].Handle(input);
            return true;
        }

        public bool Handle(Input.MouseInput input)
        {
            if (Enabled) return screens[Name].Handle(input);
            return true;
        }
    }
}
